package main;

import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;

public class OutputCSV
{
	private static final String freq2MidiTable = "frequencyMIDItable.txt";
	
	private static final String timingRes = "Timing Resolution";
	private static final String instrument = "Instrument";
	private static final String data = "Data";
	
	private static final int MIDI = 0;
	private static final int FREQUENCY = 1;
	private static final int NOTE = 2;
	private static final int OCTAVE = 3;
	
	private final int timingResolution;
	private final int instrumentNum;
	private final int volume;
	
	private final ArrayList<Integer> inputArr;
	private final ArrayList<String[]> freqConversionTables;
	
	public OutputCSV(int notesPerBeat, int instrumentNum, int volume) throws NumberFormatException, IOException
	{
		this.timingResolution = notesPerBeat;
		this.instrumentNum = instrumentNum;
		if( volume > 127 || volume < 0) {
			this.volume = 127;
		} else {
			this.volume = volume;
		}
		this.inputArr = new ArrayList<Integer>();
		this.freqConversionTables = new ArrayList<String[]>();
		generateMIDIConversionTable();
	}
	
	public void readFile( String filename ) throws IOException
	{
		FileInputStream input = new FileInputStream(filename);
		BufferedReader reader = new BufferedReader(new InputStreamReader(input));
		
		// input array
		String s = "";
		while( (s = reader.readLine()) != null )
		{
			if (s != "")
			{
				String[] arr = s.split(" ");
				for( int i = 0; i < arr.length; ++i )
				{
					inputArr.add(Integer.parseInt(arr[i]));
				}
			}
		}
		reader.close();
		input.close();
	}
	
	public void outputCSVFile( String filename ) throws IOException
	{
		FileOutputStream output = new FileOutputStream(filename);
		PrintWriter writer = new PrintWriter(output);
		int tickNum = 0;
		
		writer.println(timingRes + ":" + timingResolution);
		writer.println(instrument + ":" + instrumentNum);
		writer.println(data + ":");
		
		Iterator<Integer> i = inputArr.iterator();
		while( i.hasNext() )
		{
			int freq = i.next();
			writer.println((tickNum++) + "," + 
					convertFreqToMidiNumber(freq) + "," + volume);
		}
		writer.close();
		output.close();
	}
	
	
	private int convertFreqToMidiNumber( int freq )
	{
		Iterator<String[]> i = freqConversionTables.iterator();
		String[] prev = freqConversionTables.get(0);
		while( i.hasNext() )
		{
			String[] arr = i.next();
			double tableFrequency = Double.parseDouble(arr[FREQUENCY]);
			if( tableFrequency > freq )
			{
				// This is the first value greater than the provided freq
				// value in the table. But it might be closer to this or
				// the previous value, and we want the one with the value closest
				// to the provided freq
				double prevVal = Double.parseDouble(prev[FREQUENCY]);
				double thisDiff = Math.abs(tableFrequency - freq);
				double prevDiff = Math.abs(prevVal - freq);
				if( thisDiff < prevDiff )
				{
					return Integer.parseInt(arr[MIDI]);
				}
				else
				{
					return Integer.parseInt(prev[MIDI]);
				}
			}
			prev = arr;
		}
		return 0;
	}
	
	private void generateMIDIConversionTable() throws NumberFormatException, IOException
	{
		FileInputStream input = new FileInputStream(freq2MidiTable);
		BufferedReader reader = new BufferedReader(new InputStreamReader(input));
		
		// input array
		String s = reader.readLine(); // chop the first line
		while( (s = reader.readLine()) != null )
		{
			if (s != "")
			{
				// index 0 = MIDI
				// index 1 = FREQUENCY
				// index 2 = NOTE
				// index 3 = OCTAVE
				String[] arr = s.split("\t");
				freqConversionTables.add(arr);
			}
		}
		reader.close();
		input.close();
	}
}
